package com.zq.sysuser.service.impl;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zq.common.exception.ResultException;
import com.zq.common.util.JwtUtil;
import com.zq.minio.service.MinioService;
import com.zq.sysuser.config.MenuHelper;
import com.zq.sysuser.dao.dto.LoginDto;
import com.zq.sysuser.dao.dto.SysUserDto;
import com.zq.sysuser.dao.entity.Permission;
import com.zq.sysuser.dao.vo.SysMenuVo;
import com.zq.sysuser.dao.vo.SysUserInfoVo;
import com.zq.sysuser.dao.entity.User;
import com.zq.sysuser.mapper.UserMapper;
import com.zq.sysuser.service.IPermissionService;
import com.zq.sysuser.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 张乔
 * @since 2025-04-26
 */
@Service
@Slf4j

public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

@Autowired
private RedisTemplate<String,String> redisTemplate;




//用户登录方法
    @Override
    public String login(LoginDto loginDto) {
//        先检验验证码
        String codeRedis = redisTemplate.opsForValue().get(loginDto.getCodeKey());
        if (codeRedis==null){
            throw new ResultException(555,"验证码不存在");
        }
        if (!codeRedis.equals(loginDto.getCodeValue().toLowerCase())) {
            throw new ResultException(555, "验证码错误");
        }
//        验证码正确，删除redis中的验证码
        redisTemplate.delete(loginDto.getCodeKey());
//        用户登录
        User sysUser = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, loginDto.getUsername()));
        if(sysUser==null){
            throw new ResultException(555,"用户不存在");
        }

        String md5 = SaSecureUtil.md5(loginDto.getPassword());
        if (!md5.equals(sysUser.getPassword())){
            throw new ResultException(555,"密码错误");
        }
        //根据用户id登录，第1步，先登录上
        StpUtil.login(sysUser.getId());
        // 第2步，获取 Token  相关参数
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        // 第3步，返回给前端
        return tokenInfo.getTokenValue();
    }

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private StpInterfaceImpl stpInterface;

    @Resource
    private IPermissionService permissionService;

    //获取用户信息
    @Override
//    @Cacheable(value = "sysUserInfo",key="#token")
//    @Cacheable(value = "sysUserInfo",key="'token'")
    public SysUserInfoVo getSysUSerInfo(String token) {
        String redisUser = redisTemplate.opsForValue().get("redisSysUser"+token);
        if (StringUtils.hasText(redisUser)){
            return JSON.parseObject(redisUser,SysUserInfoVo.class);
        }


        log.error("登录用户id"+StpUtil.getSession().getLoginId());
        Integer userId = jwtUtil.getUsernameFromToken(token);
        User user = this.getById(userId);
        if(user==null){
            throw new ResultException(555,"用户不存在");
        }
        //获取用户权限（菜单）
        List<String> permissionList = stpInterface.getPermissionList(userId, "sys");
        //获取用户角色
        List<String> roleList = stpInterface.getRoleList(userId, "sys");

List<Permission> list=new ArrayList<>();
if (CollectionUtils.isEmpty(permissionList)){
            throw new ResultException(555,"用户权限为空");
        }

        permissionList.forEach(item->{
            Permission one = permissionService.getOne(new LambdaQueryWrapper<Permission>().eq(Permission::getName, item));
            list.add(one);
        });
//        已经通过递归来实现菜单的分层
        List<Permission> sysMenuTreeList = MenuHelper.BuildTree(list);

        List<SysMenuVo> sysMenuVos = buildMenus(sysMenuTreeList);
     SysUserInfoVo sysUserInfoVo=   new SysUserInfoVo(sysMenuVos,roleList,user);
       redisTemplate.opsForValue().set("redisSysUser"+token, JSON.toJSONString(sysUserInfoVo),60, TimeUnit.MINUTES);
        return sysUserInfoVo;
    }


    // 将List<SysMenu>对象转换成List<SysMenuVo>对象
    private List<SysMenuVo> buildMenus(List<Permission> menus) {
        List<SysMenuVo> sysMenuVoList = new LinkedList<>();
        for (Permission sysMenu : menus) {
            SysMenuVo sysMenuVo = new SysMenuVo();
            sysMenuVo.setTitle(sysMenu.getName());
            sysMenuVo.setName(sysMenu.getDescription());
            List<Permission> children = sysMenu.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                sysMenuVo.setChildren(buildMenus(children));
            }
            sysMenuVoList.add(sysMenuVo);
        }
        return sysMenuVoList;
    }







@Autowired
private MinioService minioService;

//    修改用户头像
    @Override
    public String updateAvatar(MultipartFile file, String token) {
        String file1= minioService.uploadFile(file);
        Integer userId = jwtUtil.getUsernameFromToken(token);
        User user = this.getById(userId);
        user.setAvatar(file1);
        this.updateById(user);
        //            删除redis中的用户信息
        redisTemplate.delete("redisSysUser"+token);
        log.info("修改头像成功");
        return file1;
    }

//    退出登录
    @Override
    public void logout(String token) {
        Integer userId = jwtUtil.getUsernameFromToken(token);
        if(userId==null){
            throw new ResultException(555,"用户不存在");
        }
        //退出登陆时，sa-token会自动删除redis中的数据
            StpUtil.logout(userId);
    }

    //修改用户的信息
    @Override
    public void updateUserInfo(User user, String token) {
        Integer userId = jwtUtil.getUsernameFromToken(token);
//        保证业务的健壮性，如果用户不存在，则抛出异常
        if(userId==null){
            throw new ResultException(555,"用户不存在");
        }
        User redisUser = this.getById(userId);
        if (redisUser==null){
            throw new ResultException(555,"用户不存在");
        }
        if (user.getUsername()==null||user.getUsername().equals("")){
            throw new ResultException(555,"用户名不能为空");
        }
        log.info("redisUser:{}",redisUser);
        log.info("user:{}",user);
//        用户修改了它的用户名，传入的用户名和redis中的用户名不一致。

        if (!redisUser.getUsername().equals(user.getUsername())){
            User user2 = this.getOne(new LambdaQueryWrapper<User>().
                    eq(User::getUsername,user.getUsername()));
//            如果数据库中已经存在了该用户名，则抛出异常
            if (user2!=null){
                throw new ResultException(555,"用户名已存在，请你再换一个");
            }
//            如果用户修改了密码，则对密码进行加密
        if(user.getPassword()!=null){
    String md5 = SaSecureUtil.md5(user.getPassword());
    user.setPassword(md5);
            }
            log.info("user:{}",user);

        user.setId(userId);
            this.updateById(user);
//            删除redis中的用户信息
            redisTemplate.delete("redisSysUser"+token);

            log.info("修改用户信息成功");
//            修改用户信息成功，直接结束方法
            return;
        }
//        用户没有修改它的用户名
//            如果用户修改了密码，则对密码进行加密
        if(user.getPassword()!=null){
            String md5 = SaSecureUtil.md5(user.getPassword());
            user.setPassword(md5);
            log.info("user:{}",user);
            user.setId(userId);
            user.setUsername(redisUser.getUsername());
            this.updateById(user);
            //            删除redis中的用户信息
            redisTemplate.delete("redisSysUser"+token);
            log.info("修改用户信息成功");
        }

    }

    //    新增用户
    @Override
    public void addUser(User user) {
        User one = this.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, user.getUsername()));
        if (one!=null){
            throw new ResultException(555,"用户名已存在");
        }

        user.setPassword(SaSecureUtil.md5(user.getPassword()));

        this.save(user);
    }



    //获取全部用户
    @Override
    public List<User> getAllUser() {
        List<User> userList = this.list();

        return userList;
    }

    //分页条件查询
    @Override
    public PageInfo<User> findByPage(SysUserDto sysUserDto, Integer pageNum, Integer pageSize) {
        LambdaQueryWrapper<User> queryWrapper=new LambdaQueryWrapper<>();
        log.info("sysUserDto:{}",sysUserDto);
//        创建查询条件，用户名模糊查询，创建时间范围查询
        queryWrapper.like(sysUserDto.getKeyword()!=null&&!StrUtil.isEmpty(sysUserDto.getKeyword())
                        ,User::getUsername,
                        sysUserDto.getKeyword())
                .ge(sysUserDto.getCreateTimeBegin()!=null&&!StrUtil.isEmpty(sysUserDto.getCreateTimeBegin())
                        ,User::getCreatedAt,
                        sysUserDto.getCreateTimeBegin())
                .le(sysUserDto.getCreateTimeEnd()!=null&&!StrUtil.isEmpty(sysUserDto.getCreateTimeEnd())
                        ,User::getCreatedAt,
                        sysUserDto.getCreateTimeEnd())
                .orderByDesc(User::getId);

PageHelper.startPage(pageNum, pageSize);
        List<User> userList = this.list(queryWrapper);
        PageInfo<User> page = new PageInfo<>(userList);
        return page;
    }

    //    修改指定用户信息
    @Override
    public void updateSysUser(User user) {
//判断用户名是否重复
        LambdaQueryWrapper<User> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(User::getUsername,user.getUsername());
        User selectOne = this.getOne(lambdaQueryWrapper);
//        用户名存在，且不是当前用户，抛出异常
        if (selectOne!=null&&!selectOne.getId().equals(user.getId())){
            throw new ResultException(555,"用户名已存在");
        }
//        对密码加密
       if(user.getPassword()!=null){

           user.setPassword(SaSecureUtil.md5(user.getPassword()));
       }
//       更新用户信息
        this.updateById(user);
    }

    //    根据id删除用户
    @Override
    public void deletedById(Integer id) {
        this.removeById(id);

    }


}
